﻿unit Dialog_ViewDict;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,Dialog_View, Vcl.ExtCtrls, RzPanel,
  ElXPThemedControl, ElTreeInplaceEditors, ElTree, Vcl.StdCtrls,System.IniFiles,
  Vcl.Mask, RzEdit, RzBtnEdt, RzButton, RzRadChk;

type
  TDialogViewDictViewType = (dvdvtSingl,dvdvtMulti);
  TDialogViewDictViewMode = (dvdvmWhole,dvdvmChild);

  TTreeStyl=class(TObject)
  public
    FormCaption:string;
    HeadCaption:string;
    MrokCaption:string;
    QuitCaption:string;
  public
    constructor Create;
  end;

  TDictFind=class(TObject)
  public
    FindType:Integer; //0:编码;1:名称
    FindCode:string;
  end;

  TDialogViewDict = class(TDialogView)
    Tree_Dict: TElTree;
    Panl_1: TRzPanel;
    Btnx_Mrok: TButton;
    Btnx_Quit: TButton;
    Edit_Find: TRzButtonEdit;
    Chkb_ALL: TRzCheckBox;
    Chkb_EXP: TRzCheckBox;
    procedure Btnx_MrokClick(Sender: TObject);
    procedure Btnx_QuitClick(Sender: TObject);
    procedure Edit_FindKeyPress(Sender: TObject; var Key: Char);
    procedure Edit_FindAltBtnClick(Sender: TObject);
    procedure Edit_FindButtonClick(Sender: TObject);
    procedure Chkb_EXPClick(Sender: TObject);
    procedure Chkb_ALLClick(Sender: TObject);
    procedure Tree_DictItemChecked(Sender: TObject; Item: TElTreeItem);
    procedure Tree_DictDblClick(Sender: TObject);
    procedure Tree_DictClick(Sender: TObject);
  private
    FViewType:TDialogViewDictViewType;
    FViewMode:TDialogViewDictViewMode;
    FListDict:TCollection;//&list of &tdict
    FHashDict:THashedStringList;//*
    FHashNode:THashedStringList;//&
    FTreeStyl:TTreeStyl;        //&
  protected
    procedure SetInitialize;override;
    procedure SetCommParams;override;
    procedure SetGridParams;override;
    procedure SetComboItems;override;
    procedure TryFreeAndNil;override;
  public
    procedure InitDict;
    procedure TreeDict(ADictFind:TDictFind=nil);
    procedure ViewNode;
    procedure ImptDict(var AListSelectEd:TCollection);
  end;

var
  DialogViewDict: TDialogViewDict;

function ViewViewDict(AListDict:TCollection;AHashNode:THashedStringList;AViewType:TDialogViewDictViewType;AViewMode:TDialogViewDictViewMode;ATreeStyl:TTreeStyl;var AListSelectEd:TCollection):Integer;

implementation

uses
  Class_Dict,Class_KzUtils,Class_UiUtils;

{$R *.dfm}

function ViewViewDict(AListDict:TCollection;AHashNode:THashedStringList;AViewType:TDialogViewDictViewType;AViewMode:TDialogViewDictViewMode;ATreeStyl:TTreeStyl;var AListSelectEd:TCollection):Integer;
begin
  try
    DialogViewDict:=TDialogViewDict.Create(nil);
    DialogViewDict.FListDict:=AListDict;
    DialogViewDict.FHashNode:=AHashNode;
    DialogViewDict.FViewType:=AViewType;
    DialogViewDict.FViewMode:=AViewMode;
    DialogViewDict.FTreeStyl:=ATreeStyl;
    Result:=DialogViewDict.ShowModal;
    if Result=Mrok then
    begin
      DialogViewDict.ImptDict(AListSelectEd);
    end;
  finally
    FreeAndNil(DialogViewDict);
  end;
end;

procedure TDialogViewDict.Btnx_MrokClick(Sender: TObject);
begin
  with Tree_Dict do
  begin
    if FViewType=dvdvtSingl then
    begin
      if SelectedCount=0 then
      begin
        ShowMessageFmt('%S',['请选择最末端节点.']);
        Exit;
      end;
      if FViewMode=dvdvmChild then
      begin
        if Selected.HasChildren then
        begin
          ShowMessageFmt('%S',['请选择最末端节点.']);
          Exit;
        end;
      end;
    end else
    if FViewType=dvdvtMulti then
    begin
      if TUiUtils.GetTreeItemCheckedCount(Tree_Dict)=0 then Exit;
    end;

    ModalResult:=mrOk;
  end;
end;

procedure TDialogViewDict.Btnx_QuitClick(Sender: TObject);
begin
  ModalResult:=mrCancel;
end;

procedure TDialogViewDict.Chkb_ALLClick(Sender: TObject);
begin
  TUiUtils.SetTreeItemCheckedState(TRzCheckBox(Sender).Checked,False,Tree_Dict);
end;

procedure TDialogViewDict.Chkb_EXPClick(Sender: TObject);
begin
  if TRzCheckBox(Sender).Checked then
  begin
    Tree_Dict.FullExpand;
  end else
  begin
    Tree_Dict.FullCollapse;
  end;
end;

procedure TDialogViewDict.Edit_FindAltBtnClick(Sender: TObject);
begin
  if TKzUtils.WarnBox('是否清空?')<>Mrok then Exit;
  TRzButtonEdit(Sender).Clear;
end;

procedure TDialogViewDict.Edit_FindButtonClick(Sender: TObject);
var
  TMPA:string;
  Find:TDictFind;
begin
  if Trim(TRzButtonEdit(Sender).Text)='' then
  begin
    TreeDict();
    Exit;
  end;
  //
  try
    Find:=TDictFind.Create;
    Find.FindType:=1;
    Find.FindCode:=Trim(TRzButtonEdit(Sender).Text);
    if TKzUtils.BoolStrMatchx(Find.FindCode,'^[A-Za-z0-9_-]+',TMPA) then
    begin
      if TMPA=Find.FindCode then
      begin
        Find.FindType:=0;
      end;
    end;
    TreeDict(Find);
  finally
    FreeAndNil(Find);
  end;
end;


procedure TDialogViewDict.Edit_FindKeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #13 then
  begin
    Edit_FindButtonClick(Edit_Find);
  end;
end;

procedure TDialogViewDict.ImptDict(var AListSelectEd: TCollection);
var
  I:Integer;
  DictA:TDict;
  DictX:TDict;
begin
  if AListSelectEd=nil then Exit;

  with Tree_Dict do
  begin
    case FViewType of
      dvdvtSingl:
      begin
        DictA:=TDict(Selected.Data);
        DictX:=TDict(AListSelectEd.Add);
        TDict.CopyIt(DictA,DictX);
      end;
      dvdvtMulti:
      begin
        for I := 0 to Items.Count-1 do
        begin
          if Items.Item[I].Checked then
          begin
            DictA:=TDict(Items.Item[I].Data);
            DictX:=TDict(AListSelectEd.Add);
            TDict.CopyIt(DictA,DictX);
          end;
        end;
      end;
    end;
  end;
end;

procedure TDialogViewDict.InitDict;
var
  I:Integer;
  Dict:TDict;
  Item:TElTreeItem;
begin
  with Tree_Dict do
  begin
    Items.Clear;
    ShowCheckBoxes:=False;
    if FViewType=dvdvtMulti then
    begin
      ShowCheckBoxes:=True;
    end;

    Items.BeginUpdate;
    for I := 0 to FListDict.Count-1 do
    begin
      Dict:=TDict(FListDict.Items[I]);
      if Dict=nil then Continue;

      Item:=Items.AddChildObject(nil,Dict.DictName,Dict);
      if FViewType=dvdvtMulti then
      begin
        Item.ShowCheckBox:=True;
      end;
    end;
    Items.EndUpdate;
  end;
end;

procedure TDialogViewDict.SetComboItems;
begin
  inherited;

end;

procedure TDialogViewDict.SetCommParams;
begin
  inherited;
  Caption:='选择字典';
  Btnx_Mrok.Caption:='确定';
  Btnx_Quit.Caption:='取消';

  if FTreeStyl<>nil then
  begin
    Caption:=FTreeStyl.FormCaption;
    Btnx_Mrok.Caption:=FTreeStyl.MrokCaption;
    Btnx_Quit.Caption:=FTreeStyl.QuitCaption;
    Tree_Dict.HeaderSections.Item[0].Text:=FTreeStyl.HeadCaption;
  end;

  Tree_Dict.HeaderSections.Item[0].Width:=self.Width - 80;
end;

procedure TDialogViewDict.SetGridParams;
begin
  inherited;

end;

procedure TDialogViewDict.SetInitialize;
begin
  inherited;
  TreeDict();
  ViewNode;
end;

procedure TDialogViewDict.TreeDict(ADictFind: TDictFind);
var
  I,M:Integer;
  cDict:TDict;
  dDict:TDict;
  ItemA:TElTreeItem;
  ItemB:TElTreeItem;

  function FindNode(AParentID:string):TElTreeItem;
  var
    X:Integer;
    ItemX:TElTreeItem;
    DictX:TDict;
  begin
    Result:=nil;
    with Tree_Dict do
    begin
      Items.BeginUpdate;
      for X:=0 to Items.Count-1 do
      begin
        ItemX:=Items.Item[X];
        DictX:=TDict(ItemX.Data);
        if IntToStr(DictX.DictIndx)=AParentID then
        begin
          Result:=ItemX;
          Break;
        end;
      end;
      Items.EndUpdate;
    end;
  end;

  function HashNode(AParentID:string):TElTreeItem;
  var
    IDXA:Integer;
  begin
    Result:=nil;
    if (FHashDict=nil) or (FHashDict.Count=0) then Exit;

    IDXA:=FHashDict.IndexOf(AParentID);
    if IDXA<>-1 then
    begin
      Result:=TElTreeItem(FHashDict.Objects[IDXA]);
    end;
  end;
begin
  if FHashDict=nil then
  begin
    FHashDict:=THashedStringList.Create;
  end;
  FHashDict.Clear;

  with Tree_Dict do
  begin
    Tree_Dict.Items.Clear;
    ShowCheckBoxes:=False;
    if FViewType=dvdvtMulti then
    begin
      ShowCheckBoxes:=True;
    end;

    Items.BeginUpdate;
    for I:=0 to FListDict.Count-1 do
    begin
      cDict:=TDict(FListDict.Items[I]);
      if cDict=nil then Continue;

      if ADictFind<>nil then
      begin
        if ADictFind.FindType=0 then
        begin
          //#if Pos(ADictFind.FindCode,Dict.DictCode)<0 then Continue;
          //if not TKzUtils.CompareTextLike(ADictFind.FindCode,Dict.DictCode) then Continue;
          if Pos(ADictFind.FindCode,cDict.DictCode)<=0 then Continue;
        end else
        if ADictFind.FindType=1 then
        begin
          if Pos(ADictFind.FindCode,cDict.DictName)<=0 then Continue;
        end;
      end;

      if (Trim(cDict.ParentID)='0') or (Trim(cDict.ParentID)='') then
      begin
        ItemB:=Items.AddChildObject(nil,Format('%S_%S',[cDict.DictCode,cDict.DictName]),cDict);
        FHashDict.AddObject(IntToStr(cDict.DictIndx),ItemB);
      end else
      begin
        //#Item:=FindNode(Dict.ParentID);
        ItemA:=HashNode(cDict.ParentID);
        ItemB:=Items.AddChildObject(ItemA,Format('%S_%S',[cDict.DictCode,cDict.DictName]),cDict);
        FHashDict.AddObject(IntToStr(cDict.DictIndx),ItemB);
      end;

      if FViewType=dvdvtMulti then
      begin
        ItemB.ShowCheckBox:=True;
      end;
    end;


    if FViewType=dvdvtSingl then
    begin
      for I := Items.Count-1 downto 0 do
      begin
        ItemA:=Items.Item[I];
        if ItemA=nil then Continue;
        cDict:=TDict(ItemA.Data);
        if cDict=nil then Continue;
        //if StrToIntDef(cDict.ParentID,0)<>0 then Continue;

        if not ItemA.HasChildren then
        begin
          for M := 0 to FListDict.Count-1 do
          begin
            dDict:=TDict(FListDict.Items[M]);
            if StrToIntDef(dDict.ParentID,0)=cDict.DictIndx then
            begin
              Items.Delete(ItemA);
              Break;
            end;
          end;
        end;
      end;
    end;

    {#if ADictFind<>nil then
    begin
      for I := Items.Count-1 downto 0 do
      begin
        ItemA:=Items.Item[I];
        if ItemA.HasChildren then Continue;
        
        Dict:=TDict(ItemA.Data);
        if Dict=nil then Continue;

        if ADictFind.FindType=0 then
        begin
          //#if Pos(ADictFind.FindCode,Dict.DictCode)<0 then Continue;
          //if not TKzUtils.CompareTextLike(ADictFind.FindCode,Dict.DictCode) then Continue;
          if Pos(ADictFind.FindCode,Dict.DictCode)<=0 then
          begin
            //ShowMessageFmt('%S:%S:%S',[ADictFind.FindCode,Dict.DictCode,Dict.DictName]);
            Tree_Dict.Items.Delete(Items.Item[I]);
          end;
        end else
        if ADictFind.FindType=1 then
        begin
          if Pos(ADictFind.FindCode,Dict.DictName)<=0 then
          begin
            Tree_Dict.Items.Delete(Items.Item[I]);
          end;
        end;
      end;
    end;}
    Items.EndUpdate;
  end;
end;

procedure TDialogViewDict.Tree_DictClick(Sender: TObject);
var
  Item:TElTreeItem;
begin
  with Tree_Dict do
  begin
    Item:=Tree_Dict.Selected;
    if Item=nil then Exit;

    if Item.HasChildren then
    begin
      Item.Expanded:=not Item.Expanded;
    end;
  end;
end;

procedure TDialogViewDict.Tree_DictDblClick(Sender: TObject);
begin
  Btnx_MrokClick(Btnx_Mrok);
end;

procedure TDialogViewDict.Tree_DictItemChecked(Sender: TObject;
  Item: TElTreeItem);
begin
  if Item.Checked then
  begin
    TUiUtils.SetItemNextChecked(TElTree(Sender),Item,True);
  end else
  begin
    TUiUtils.SetItemNextChecked(TElTree(Sender),Item,False);
    TUiUtils.SetItemPrevChecked(TElTree(Sender),Item,False);
  end;
end;

procedure TDialogViewDict.TryFreeAndNil;
begin
  inherited;
  if FHashDict<>nil then FreeAndNil(FHashDict);
  
end;

procedure TDialogViewDict.ViewNode;
var
  I:Integer;
  DictA:TDict;
  DictX:TDict;
  ItemA:TElTreeItem;
  ItemX:TElTreeItem;
begin
  if (FHashNode=nil) or (FHashNode.Count=0) then Exit;

  if FViewType=dvdvtMulti then
  begin
    with Tree_Dict do
    begin
      Items.BeginUpdate;
      for I := 0 to Items.Count-1 do
      begin
        ItemA:=Items.Item[I];
        DictA:=TDict(ItemA.Data);
        if DictA=nil then Continue;

        if FHashNode.IndexOf(Format('%D',[DictA.DictIndx]))<>-1 then
        begin
          ItemA.Checked:=True;

          {#while AItem.Parent<>nil do
          begin
            AItem:=AItem.Parent;
            AItem.Expanded:=True;
          end;}

          ItemX:=ItemA.Parent;
          while ItemX<>nil do
          begin
            ItemX.Expanded:=True;
            ItemX:=ItemX.Parent;
          end;
        end;
      end;
      Items.EndUpdate;
    end;
  end else
  if FViewType=dvdvtSingl then
  begin
    DictX:=TDict(FHashNode.Objects[0]);

    with Tree_Dict do
    begin
      //****when use topitem,donot user beginupdate&endupdate
      //Items.BeginUpdate;
      for I := 0 to Items.Count-1 do
      begin
        ItemA:=Items.Item[I];
        DictA:=TDict(ItemA.Data);
        if DictA=nil then Continue;

        if DictA.DictIndx=DictX.DictIndx then
        begin
          ItemA.Selected:=True;
          ItemA.Expanded:=True;
          ItemX:=ItemA.Parent;
          while ItemX <>nil do
          begin
            ItemX.Expanded:=True;
            ItemX:=ItemX.Parent;
          end;

          Tree_Dict.Selected:=ItemA;
          if not Tree_Dict.IsInView(ItemA) then
          begin
            Tree_Dict.TopItem:=ItemA;
          end;


          Break;
        end;
      end;
      //Items.EndUpdate;
    end;
  end;
end;

{ TTreeStyl }

constructor TTreeStyl.Create;
begin
  FormCaption:='选择字典';
  HeadCaption:='';
  MrokCaption:='确定';
  QuitCaption:='取消';
end;

end.
